/**
* \file
*
* \brief Empty user application template
*
*/

/**
* \mainpage User Application template doxygen documentation
*
* \par Empty user application template
*
* Bare minimum empty user application template
*
* \par Content
*
* -# Include the ASF header files (through asf.h)
* -# Minimal main function that starts with a call to board_init()
* -# "Insert application code here" comment
*
*/

/*
* Include header files for all drivers that have been imported from
* Atmel Software Framework (ASF).
*/
#include "defines.h"
#include <avr\sleep.h>
#include <stdio.h>
#include <stdlib.h>
#include <asf.h>
#include <math.h>
#include "globals.h"
#include "OLED.h"
#include "MS5541.h"
#include "PCInt.h"
#include "Timers.h"
#include "testFunctions.h"
#include "Deco.h"
#include "menu.h"
#include "dive.h"
#include "logbook.h"

void switch_to_idle(void);
void switch_from_idle(void);

//static char printString[22];


int main (void)
{
	int i, dT;
	float depth = 0.0;
	float delta_depth = 0.0;
	float delta_depth_filtered = 0.0;
	float old_depth = 0.0;
	deco_info_t deco_info;
	int16_t vario_height = 0;
	float p_surface_bar = 1.013;
	float p_no_deco[16];
	int8_t deco_steps = 3;
	float p_ambient_bar;
	
#ifdef TEST_SENSOR_MODE
	long unsigned int pressure_mbar_average = 0;
	char printString[20];
#endif	
	
	board_init();
	init_Timer2();
	delay_ms(1000);		//wait 1 s until 32 kHz clock oscillates

	MCUCR |= _BV(JTD);			//switch off JTAG
	MCUCR |= _BV(JTD);

	OLED_Init();
	Fill_RAM(0x00,0x00);		// Clear Screen

#ifdef TEST_MODE
	Show_String(1,"RESET",0xFF,0xFF,0x02, 0x00);
#endif

	init_PCInt();
	init_MS5541();
	get_coeffs(&calib_words);
	dT = get_temp_diff(&calib_words);
	temperature = get_temperature(dT, &calib_words);
	pressure_mbar = 0;
	for (i =0; i<8; i++){
		pressure_mbar += get_pressure(dT, &calib_words);
	}
	pressure_mbar = pressure_mbar >> 3;
	p_surface_mbar = pressure_mbar;
	
	reset_p_tissues((float)p_surface_mbar/1000.0);

	sei();
	set_sleep_mode(SLEEP_MODE_PWR_SAVE);					//Selecting power save mode as the sleep mode to be used
	

	while(1){
		while (!new_data){};							// wait for new data (new_data will be set by TIMER2_OVF)
		new_data = 0;
		switch (state){
			case IDLE:
				switch_to_idle();
				sleep_enable();
				while (state == IDLE){
					sei();
					sleep_cpu();
				}
				sleep_disable();
				switch_from_idle();
				break;
			case MENU:
#ifdef TEST_SENSOR_MODE
				Show_String(1,"Testing Sensor",0xFF,0xFF,0x02, 0x00);
				pressure_mbar_average = 7*pressure_mbar_average + (pressure_mbar<<3);
				pressure_mbar_average = pressure_mbar_average>>3;
				show_measurements();
				sprintf(printString,"%4lu hPa",pressure_mbar_average>>3);
				Show_String(1,printString,0xFF,0xFF,0x00,0x30);

				break;
#else
			
				if (new_state){
					Fill_RAM(0x00,0x00);
					new_state = 0;
				}
				menu();
				break;
#endif
			case DIVE:
				if (new_state){
					new_state = 0;
					prepare_dive_screen();
					p_surface_bar = (float)p_surface_mbar/1000.0;
					compute_p_no_deco(p_surface_bar, p_no_deco);
					old_depth = 0.0;
				}
				if (salt_water){
					depth = (pressure_mbar - p_surface_mbar)/101.4;
				} else {
					depth = (pressure_mbar - p_surface_mbar)/98.0;
				}
				delta_depth = depth - old_depth;
				delta_depth_filtered = delta_depth_filtered + delta_depth;
				delta_depth_filtered = delta_depth_filtered/2.0;
				vario_height = delta_depth_filtered*120.0;
				old_depth = depth;
				if (depth > max_depth){
					max_depth = depth;
				}
				if (temperature < min_temperature){
					min_temperature = temperature;
				}
				p_ambient_bar = (float)pressure_mbar/1000.0;
				deco_info = compute_deco_information(p_ambient_bar, p_surface_bar, p_no_deco,deco_steps, percentage_N2);
				update_dive_screen(deco_info, 10*depth, dive_time/60, temperature/10, vario_height);
				break;
			case SURFACED:
				if (new_state){
					new_state = 0;
					surfaced(max_depth, duration_of_dive);
					Draw_Rectangle(0x00,Max_Column,0x3F,0x5F,0x01,0xC6,0x18);
					show_string_zoomed("Max. Depth",0xC6,0x18,0x02,0x41,0x01);
					Draw_Rectangle(0x00,Max_Column,0x5F,0x7F,0x01,0xC6,0x18);
					show_string_zoomed("Duration",0xC6,0x18,0x02,0x61,0x01);
				}
				break;
		}
	}

}


void switch_to_idle(void){
	Fill_Block(0x00, Max_Column, 0x00, 0x07, 0x00, 0x00);
#ifdef TEST_MODE
	Show_String(1,"Going to sleep...",0xFF,0xFF,0x02, 0x00);
	delay_ms(500);
#endif
	Set_Display_On_Off(0);
#ifdef TEST_MODE
	PORTB &= 0b11111100;		//switch all except 3V3 DC/DC converter off
#else
	PORTB &= 0b11111000;		//switch all DC/DC converters off
#endif
	PORTA = 0x00;
	PORTD = 0x00;
}

void switch_from_idle(void){
	PORTA = (0<<PA7)|(0<<PA6)|(0<<PA5)|(1<<PA4)|(1<<PA3)|(1<<PA2)|(0<<PA1)|(1<<PA0);
	DDRA  = (0<<PA7)|(0<<PA6)|(0<<PA5)|(1<<PA4)|(1<<PA3)|(1<<PA2)|(1<<PA1)|(1<<PA0);
	PORTD = 0x00;
	DDRD  = 0xFF;
	PORTB |= 0b00000111;		//switch all DC/DC converter on
	delay_ms(100);
	OLED_Init();
	Fill_RAM(0x00,0x00);		// Clear Screen
#ifdef TEST_MODE	
	Show_String(1,"Waking up",0xFF,0xFF,0x02, 0x00);
	show_measurements();
	delay_ms(500);
#endif
}

